package com.zeratul.web.interceptor;

import cn.hutool.core.util.ObjectUtil;
import com.zeratul.common.core.context.DataContextHolde;
import com.zeratul.common.trace.TraceIdManager;
import com.zeratul.web.interceptor.base.BaseHandlerInterceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Optional;

import static com.zeratul.common.core.constant.MdcConstants.REQUEST_URL_KEY;
import static com.zeratul.common.core.constant.MdcConstants.TRACE_ID;


/**
 * 获取请求URL，并且设置到Log中的前置拦截器
 */
@Component
public class WebRequestLogInterceptor extends BaseHandlerInterceptor {

    @Autowired
    private TraceIdManager traceIdManager;

    /**
     * 前置拦截器
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //从MDC中获取URL
        String requestUrl = MDC.get(REQUEST_URL_KEY);
        if (ObjectUtil.isEmpty(requestUrl)) {
            requestUrl = request.getRequestURI();
            MDC.put(REQUEST_URL_KEY, requestUrl);
        }

        //获取全局TraceId
        String traceId = MDC.get(TRACE_ID);
        if (ObjectUtil.isEmpty(traceId)) {

            //从请求头获取TraceId，如果获取不到则生成一个
            traceId = Optional.ofNullable(request.getHeader(TRACE_ID))
                    .orElseGet(() -> traceIdManager.getTraceId());
            MDC.put(TRACE_ID, traceId);
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //回收MDC资源
        MDC.clear();
        //全局上下文资源回收
        DataContextHolde.clear();
    }

    /**
     * 拦截器的拦截Path路径
     *
     * @return
     */
    @Override
    public String path() {
        return "/**";
    }
}
